package com.cosmosource.core.advice;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 全局异常处理
 *
 * @author Hsiao Lin
 */
@Slf4j
@RestControllerAdvice
public class ExceptionAdvice {

    /**
     * 参数无效
     *
     * @param e       参数校验失败异常信息
     * @param request HttpServletRequest
     * @return ResponseEntity<Map < String, Object>>
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, Object>> methodArgumentNotValidHandler(MethodArgumentNotValidException e, HttpServletRequest request) {
        return ResponseEntity.error("参数校验失败", buildResponseBody(e.getBindingResult().getFieldError().getDefaultMessage(), request));
    }

    /**
     * 参数违反约束，javax扩展定义
     *
     * @param e       参数违反约束异常信息
     * @param request HttpServletRequest
     * @return ResponseEntity<Map < String, Object>>
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Map<String, Object>> constraintViolationHandler(ConstraintViolationException e, HttpServletRequest request) {
        return ResponseEntity.error("参数违反约束异常", buildResponseBody(e.getMessage(), request));
    }

    /**
     * 参数绑定失败
     *
     * @param e       绑定失败异常信息
     * @param request HttpServletRequest
     * @return ResponseEntity<Map < String, Object>>
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BindException.class)
    public ResponseEntity<Map<String, Object>> bindHandler(BindException e, HttpServletRequest request) {
        return ResponseEntity.error("参数绑定失败异常", buildResponseBody(e.getMessage(), request));
    }

    /**
     * 参数缺失
     *
     * @param e       参数缺失异常信息
     * @param request HttpServletRequest
     * @return ResponseEntity<Map < String, Object>>
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity<Map<String, Object>> missingServletRequestParameterHandler(MissingServletRequestParameterException e, HttpServletRequest request) {
        return ResponseEntity.error("参数缺失异常", buildResponseBody(e.getMessage(), request));
    }


    /**
     * 参数类型不匹配
     *
     * @param e       参数类型不匹配异常信息
     * @param request HttpServletRequest
     * @return ResponseEntity<Map < String, Object>>
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(TypeMismatchException.class)
    public ResponseEntity<Map<String, Object>> typeMismatchHandler(TypeMismatchException e, HttpServletRequest request) {
        return ResponseEntity.error("参数类型不匹配异常", buildResponseBody(e.getMessage(), request));
    }

    /**
     * 自定义全局异常处理
     *
     * @param e       全局异常信息
     * @param request HttpServletRequest
     * @return ResponseEntity<Map < String, Object>>
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(GlobalException.class)
    public ResponseEntity<Map<String, Object>> globalHandler(GlobalException e, HttpServletRequest request) {
        return ResponseEntity.error("服务端发生异常", buildResponseBody(e.getMessage(), request));
    }

    /**
     * 自定义异常处理
     *
     * @param e       异常信息
     * @param request HttpServletRequest
     * @return ResponseEntity<Map < String, Object>>
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Map<String, Object>> globalHandler(Exception e, HttpServletRequest request) {
        log.error("服务端异常", e);
        return ResponseEntity.error("服务端异常", buildResponseBody(e.getMessage(), request));
    }

    /**
     * 封装响应体
     *
     * @param error   错误信息
     * @param request 请求对象
     * @return Map<String, Object> 响应体
     */
    private Map<String, Object> buildResponseBody(String error, HttpServletRequest request) {
        // 响应体
        Map<String, Object> body = new LinkedHashMap<>(3);
        // 时间戳
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        body.put("timestamp", LocalDateTime.now().format(dateTimeFormatter));
        // 请求路径
        body.put("path", request.getRequestURI());
        // 请求方法
        body.put("method", request.getMethod());


        body.put("info", error);

        return body;
    }
}
